package com.example.publishdemo.publishservice;

import com.example.publishdemo.publishservice.enums.PublishServicesType;
import com.example.publishdemo.publishservice.event.MyPublishEvent;
import com.example.publishdemo.publishservice.event.MyPublishEventForAsync;
import com.example.publishdemo.publishservice.event.MyPublishEventForSync;
import com.example.publishdemo.publishservice.exception.InvokeServiceException;
import com.example.publishdemo.publishservice.invoke.InvokeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import static com.example.publishdemo.publishservice.enums.PublishServicesType.CALL_ZHANG_SAN;
import static com.example.publishdemo.publishservice.enums.PublishServicesType.SCHOOL_NOTICE;

/**
 * 该类其实主要是注册一个事件监听器，
 * 可以不写该类，通过配置文件配置，
 * 写该类的原因：
 * 1、使项目结构清晰
 * 2、不用谢烦人的xml配置
 * 3、我们也可以重写该方法类标注不同的服务实现类，便于服务的管理
 * 比如：消息通知服务，事件推送服务。。。。。。。
 */
@Component
public class MyPublishEventListener {


    private InvokeService callZhangSanInvokeService;

    private InvokeService schoolNoticeInvokeService;

    private Map<String, InvokeService> serviceMap;

    @Autowired
    public MyPublishEventListener(@Qualifier("callZhangSan") InvokeService callZhangSanInvokeService,
                                  @Qualifier("schoolNotice") InvokeService schoolNoticeInvokeService) {
        this.callZhangSanInvokeService = callZhangSanInvokeService;
        this.schoolNoticeInvokeService = schoolNoticeInvokeService;
        initServiceMap();
    }

    private void initServiceMap() {
        this.serviceMap = new HashMap<>(2);
        serviceMap.put(CALL_ZHANG_SAN.getCode(), callZhangSanInvokeService);
        serviceMap.put(SCHOOL_NOTICE.getCode(), schoolNoticeInvokeService);
    }

    /**
     * 异步通知
     *
     * @param myPublishEvent
     */
    @Async
    @EventListener //该类中最核心的注解，一定要有，要不该类就失去了存在的意义
    public void processEventForAsync(MyPublishEventForAsync myPublishEvent) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            //不用往外抛，使用的异步模式，自己内部消化就好了，子服务可以retry等操作
        }
        String explain = "莫着急，我刚睡醒，我要开始转发了";
        String serviceName = myPublishEvent.getPublishServicesType().getName();
        String msg = myPublishEvent.getMessage();
        System.out.println(String.format("对%s的喊话到：%s", serviceName, explain));

        System.out.println(
                String.format("我现在转发的服务：%s \n 发送的消息是：%s", serviceName, msg));
        //转发起始对应的就是另外一种流程，该模式已经结束


        //服务转发可通过桥接模式实现进一步抽象
        transmit(myPublishEvent);

    }


    @EventListener //该类中最核心的注解，一定要有，要不该类就失去了存在的意义
    public void processEventForSync(MyPublishEventForSync myPublishEvent) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            //不用往外抛，使用的异步模式，自己内部消化就好了，子服务可以retry等操作
        }
        String explain = "莫着急，我刚睡醒，我要开始转发了";
        String serviceName = myPublishEvent.getPublishServicesType().getName();
        String msg = myPublishEvent.getMessage();
        System.out.println(String.format("对%s的喊话到：%s", serviceName, explain));

        System.out.println(
                String.format("我现在转发的服务：%s \n 发送的消息是：%s", serviceName, msg));
        //转发起始对应的就是另外一种流程，该模式已经结束
        transmit(myPublishEvent);

    }


    private void transmit(MyPublishEvent myPublishEvent) {
        //我是通过类型服务识别码进行的转发
        PublishServicesType servicesType = myPublishEvent.getPublishServicesType();
        if (servicesType == null) {
            System.out.println(String.format("服务识别码错误：%s", myPublishEvent.getMessage()));
        }
        InvokeService service = serviceMap.get(servicesType.getCode());
        if (service == null) {
            System.out.println(String.format("服务识别码错误：%s", servicesType.getName()));
        }
        try {
            service.invoke(myPublishEvent.getMessage());
        } catch (InvokeServiceException e) {
            System.out.println(String.format("服务通知异常：%s", e.getMessage()));
        }
    }

}
